home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 1 / QRZ Ham Radio Callsign Database - December 1993.iso / ucsd / packet / tcpip / sys5 / iscwmpst.z / iscwmpst / tcp / src / arp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-24  |  8.8 KB  |  316 lines

  1. /* @(#) $Header: arp.c,v 1.9 91/09/24 05:52:18 deyke Exp $ */
  2.  
  3. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  4.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  5.  * Copyright 1991 Phil Karn, KA9Q
  6.  */
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "iface.h"
  11. #include "enet.h"
  12. #include "ax25.h"
  13. #include "icmp.h"
  14. #include "ip.h"
  15. #include "arp.h"
  16. #include "icmp.h"
  17.  
  18. static void arp_output __ARGS((struct iface *iface,int hardware,int32 target));
  19.  
  20. /* Hash table headers */
  21. struct arp_tab *Arp_tab[HASHMOD];
  22.  
  23. struct arp_stat Arp_stat;
  24.  
  25. /* Resolve an IP address to a hardware address; if not found,
  26.  * initiate query and return NULLCHAR.  If an address is returned, the
  27.  * interface driver may send the packet; if NULLCHAR is returned,
  28.  * res_arp() will have saved the packet on its pending queue,
  29.  * so no further action (like freeing the packet) is necessary.
  30.  */
  31. char *
  32. res_arp(iface,hardware,target,bp)
  33. struct iface *iface;    /* Pointer to interface block */
  34. int16 hardware;         /* Hardware type */
  35. int32 target;           /* Target IP address */
  36. struct mbuf *bp;        /* IP datagram to be queued if unresolved */
  37. {
  38.     register struct arp_tab *arp;
  39.     struct ip ip;
  40.  
  41.     if((arp = arp_lookup(hardware,target)) != NULLARP && arp->state == ARP_VALID)
  42.         return arp->hw_addr;
  43.     if(arp != NULLARP){
  44.         /* Earlier packets are already pending, kick this one back
  45.          * as a source quench
  46.          */
  47.         ntohip(&ip,&bp);
  48.         icmp_output(&ip,bp,ICMP_QUENCH,0,NULL);
  49.         free_p(bp);
  50.     } else {
  51.         /* Create an entry and put the datagram on the
  52.          * queue pending an answer
  53.          */
  54.         arp = arp_add(target,hardware,NULLCHAR,0);
  55.         enqueue(&arp->pending,bp);
  56.         arp_output(iface,hardware,target);
  57.     }
  58.     return NULLCHAR;
  59. }
  60. /* Handle incoming ARP packets. This is almost a direct implementation of
  61.  * the algorithm on page 5 of RFC 826, except for:
  62.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  63.  *    pending a reply to our ARP request.
  64.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  65.  * 3. Requests for IP addresses listed in our table as "published" are
  66.  *    responded to, even if the address is not our own.
  67.  */
  68. void
  69. arp_input(iface,bp)
  70. struct iface *iface;
  71. struct mbuf *bp;
  72. {
  73.     struct arp arp;
  74.     struct arp_tab *ap;
  75.     struct arp_type *at;
  76.     int i;
  77.     struct route *rp;
  78.  
  79.     Arp_stat.recv++;
  80.     if(ntoharp(&arp,&bp) == -1)     /* Convert into host format */
  81.         return;
  82.     if(arp.hardware >= NHWTYPES){
  83.         /* Unknown hardware type, ignore */
  84.         Arp_stat.badtype++;
  85.         return;
  86.     }
  87.     at = &Arp_type[arp.hardware];
  88.     if(arp.protocol != at->iptype){
  89.         /* Unsupported protocol type, ignore */
  90.         Arp_stat.badtype++;
  91.         return;
  92.     }
  93.     if(uchar(arp.hwalen) > MAXHWALEN || uchar(arp.pralen) != sizeof(int32)){
  94.         /* Incorrect protocol addr length (different hw addr lengths
  95.          * are OK since AX.25 addresses can be of variable length)
  96.          */
  97.         Arp_stat.badlen++;
  98.         return;
  99.     }
  100.     if(arp.sprotaddr == 0L || arp.tprotaddr == 0L) {
  101.         /* We are going to dead-end references for [0.0.0.0], since
  102.          * experience shows that these cause total lock up -- N1BEE
  103.          */
  104.         Arp_stat.badaddr++;
  105.         return;
  106.     }
  107.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  108.         /* This guy is trying to say he's got the broadcast address! */
  109.         Arp_stat.badaddr++;
  110.         return;
  111.     }
  112.     /* If this guy is already in the table, update its entry
  113.      * unless it's a manual entry (noted by the lack of a timer)
  114.      */
  115.     ap = NULLARP;   /* ap plays the role of merge_flag in the spec */
  116.     if((ap = arp_lookup(arp.hardware,arp.sprotaddr)) != NULLARP
  117.      && dur_timer(&ap->timer) != 0){
  118.         ap = arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  119.     }
  120.     /* See if we're the address they're looking for */
  121.     if(ismyaddr(arp.tprotaddr) != NULLIF){
  122.         if(ap == NULLARP)       /* Only if not already in the table */
  123.             arp_add(arp.sprotaddr,arp.hardware,arp.shwaddr,0);
  124.  
  125.         if(arp.opcode == ARP_REQUEST){
  126.             /* Swap sender's and target's (us) hardware and protocol
  127.              * fields, and send the packet back as a reply
  128.              */
  129.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  130.             /* Mark the end of the sender's AX.25 address
  131.              * in case he didn't
  132.              */
  133.             if(arp.hardware == ARP_AX25)
  134.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  135.  
  136.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  137.             arp.tprotaddr = arp.sprotaddr;
  138.             arp.sprotaddr = iface->addr;
  139.             arp.opcode = ARP_REPLY;
  140.             if((bp = htonarp(&arp)) == NULLBUF)
  141.                 return;
  142.  
  143.             if(iface->forw != NULLIF)
  144.                 (*iface->forw->output)(iface->forw,
  145.                  arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  146.             else
  147.                 (*iface->output)(iface,arp.thwaddr,
  148.                  iface->hwaddr,at->arptype,bp);
  149.             Arp_stat.inreq++;
  150.         } else {
  151.             Arp_stat.replies++;
  152.         }
  153.     } else if(arp.opcode == ARP_REQUEST
  154.      && (ap = arp_lookup(arp.hardware,arp.tprotaddr)) != NULLARP
  155.      && (ap->pub || (rp = rt_lookup(arp.tprotaddr)) && rp->iface != iface)){
  156.         /* Otherwise, respond if the guy he's looking for is
  157.          * published in our table or on a different interface.
  158.          */
  159.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  160.         memcpy(arp.shwaddr,ap->pub?ap->hw_addr:iface->hwaddr,at->hwalen);
  161.         arp.tprotaddr = arp.sprotaddr;
  162.         arp.sprotaddr = ap->ip_addr;
  163.         arp.opcode = ARP_REPLY;
  164.         if((bp = htonarp(&arp)) == NULLBUF)
  165.             return;
  166.         if(iface->forw != NULLIF)
  167.             (*iface->forw->output)(iface->forw,
  168.              arp.thwaddr,iface->forw->hwaddr,at->arptype,bp);
  169.         else
  170.             (*iface->output)(iface,arp.thwaddr,
  171.              iface->hwaddr,at->arptype,bp);
  172.         Arp_stat.inreq++;
  173.     } else if(arp.opcode == REVARP_REQUEST){
  174.         for(i=0;i<HASHMOD;i++)
  175.             for(ap = Arp_tab[i];ap != NULLARP;ap = ap->next)
  176.                 if(memcmp(ap->hw_addr,arp.thwaddr,at->hwalen) == 0)
  177.                     goto found;
  178.     found:  if(ap != NULLARP && ap->pub){
  179.             memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  180.             arp.tprotaddr = ap->ip_addr;
  181.             arp.sprotaddr = iface->addr;
  182.             arp.opcode = REVARP_REPLY;
  183.             if((bp = htonarp(&arp)) == NULLBUF)
  184.                 return;
  185.             if(iface->forw != NULLIF)
  186.                 (*iface->forw->output)(iface->forw,
  187.                  arp.thwaddr,iface->forw->hwaddr,REVARP_TYPE,bp);
  188.             else
  189.                 (*iface->output)(iface,arp.thwaddr,
  190.                  iface->hwaddr,REVARP_TYPE,bp);
  191.             Arp_stat.inreq++;
  192.         }
  193.     }
  194. }
  195. /* Add an IP-addr / hardware-addr pair to the ARP table */
  196. struct arp_tab *
  197. arp_add(ipaddr,hardware,hw_addr,pub)
  198. int32 ipaddr;           /* IP address, host order */
  199. int16 hardware;         /* Hardware type */
  200. char *hw_addr;          /* Hardware address, if known; NULLCHAR otherwise */
  201. int pub;                /* Publish this entry? */
  202. {
  203.     struct mbuf *bp;
  204.     register struct arp_tab *ap;
  205.     struct arp_type *at;
  206.     unsigned hashval;
  207.  
  208.     if(hardware >=NHWTYPES)
  209.         return NULLARP; /* Invalid hardware type */
  210.     at = &Arp_type[hardware];
  211.  
  212.     if((ap = arp_lookup(hardware,ipaddr)) == NULLARP){
  213.         /* New entry */
  214.         ap = (struct arp_tab *)callocw(1,sizeof(struct arp_tab));
  215.         ap->hw_addr = mallocw(at->hwalen);
  216.         ap->timer.func = arp_drop;
  217.         ap->timer.arg = ap;
  218.         ap->hardware = hardware;
  219.         ap->ip_addr = ipaddr;
  220.  
  221.         /* Put on head of hash chain */
  222.         hashval = hash_ip(ipaddr);
  223.         ap->prev = NULLARP;
  224.         ap->next = Arp_tab[hashval];
  225.         Arp_tab[hashval] = ap;
  226.         if(ap->next != NULLARP){
  227.             ap->next->prev = ap;
  228.         }
  229.     }
  230.     if(hw_addr == NULLCHAR){
  231.         /* Await response */
  232.         ap->state = ARP_PENDING;
  233.         set_timer(&ap->timer,Arp_type[hardware].pendtime * 1000L);
  234.     } else {
  235.         /* Response has come in, update entry and run through queue */
  236.         ap->state = ARP_VALID;
  237.         set_timer(&ap->timer,ARPLIFE*1000L);
  238.         memcpy(ap->hw_addr,hw_addr,at->hwalen);
  239.         ap->pub = pub;
  240.         arp_savefile();
  241.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  242.             ip_route(NULLIF,bp,0);
  243.     }
  244.     start_timer(&ap->timer);
  245.     return ap;
  246. }
  247.  
  248. /* Remove an entry from the ARP table */
  249. void
  250. arp_drop(p)
  251. void *p;
  252. {
  253.     register struct arp_tab *ap;
  254.  
  255.     ap = (struct arp_tab *)p;
  256.     if(ap == NULLARP)
  257.         return;
  258.     stop_timer(&ap->timer); /* Shouldn't be necessary */
  259.     if(ap->next != NULLARP)
  260.         ap->next->prev = ap->prev;
  261.     if(ap->prev != NULLARP)
  262.         ap->prev->next = ap->next;
  263.     else
  264.         Arp_tab[hash_ip(ap->ip_addr)] = ap->next;
  265.     free_q(&ap->pending);
  266.     free(ap->hw_addr);
  267.     free((char *)ap);
  268. }
  269.  
  270. /* Look up the given IP address in the ARP table */
  271. struct arp_tab *
  272. arp_lookup(hardware,ipaddr)
  273. int16 hardware;
  274. int32 ipaddr;
  275. {
  276.     register struct arp_tab *ap;
  277.  
  278.     arp_loadfile();
  279.     for(ap = Arp_tab[hash_ip(ipaddr)]; ap != NULLARP; ap = ap->next){
  280.         if(ap->ip_addr == ipaddr && ap->hardware == hardware)
  281.             break;
  282.     }
  283.     return ap;
  284. }
  285. /* Send an ARP request to resolve IP address target_ip */
  286. static void
  287. arp_output(iface,hardware,target)
  288. struct iface *iface;
  289. int16 hardware;
  290. int32 target;
  291. {
  292.     struct arp arp;
  293.     struct mbuf *bp;
  294.     struct arp_type *at;
  295.  
  296.     at = &Arp_type[hardware];
  297.     if(iface->output == NULLFP)
  298.         return;
  299.  
  300.     arp.hardware = hardware;
  301.     arp.protocol = at->iptype;
  302.     arp.hwalen = at->hwalen;
  303.     arp.pralen = sizeof(int32);
  304.     arp.opcode = ARP_REQUEST;
  305.     memcpy(arp.shwaddr,iface->hwaddr,at->hwalen);
  306.     arp.sprotaddr = iface->addr;
  307.     memset(arp.thwaddr,0,at->hwalen);
  308.     arp.tprotaddr = target;
  309.     if((bp = htonarp(&arp)) == NULLBUF)
  310.         return;
  311.     (*iface->output)(iface,at->bdcst,
  312.         iface->hwaddr,at->arptype,bp);
  313.     Arp_stat.outreq++;
  314. }
  315.  
  316.